home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
t_unix
/
j109lxa4.tar
/
curses.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-04
|
21KB
|
1,019 lines
/*
* Intelligent session manager using curses. Options include ANSI X3.64
* emulation with both VTx00 and PC graphics.
*
* Brandon S. Allbery KF8NH
* No copyright, copyleft, copysideways, copytwisted, ....
*/
#include <curses.h>
#include <term.h>
#undef FALSE
#undef TRUE
/* This nonsense WILL go away... */
#ifdef linux
#define _tmarg _regtop
#define _bmarg _regbottom
#define wbkgdset(w,attr) ((w)->_bkgd = (attr))
#ifndef getattrs
#define getattrs(w) ((w)->_attrs)
#endif
#endif
#include "hardware.h"
#include "proc.h"
#include "socket.h"
#undef tputs
#include "tty.h"
#include "sessmgr.h"
#include "config.h"
#ifdef SM_CURSES
#ifdef linux
extern int isatty __ARGS((int));
#endif
extern struct sessmgr_sw curses_sessmgr; /* forward declaration */
static int Suspense, initted;
static TERMINAL *my_term;
static void *curscreen;
#if 0
/* colors - this is a mess */
static char *color_pair_map;
#endif
struct keytrie
{
enum {KT_DEF, KT_TRIE, KT_TVAL, KT_VAL} kt_type; /* type of entry */
int kt_tval; /* if a TVAL, the timed-out value */
union
{
struct keytrie *ktu_trie; /* sub-trie */
#define kt_trie kt_u.ktu_trie
int ktu_val; /* value */
#define kt_val kt_u.ktu_val
} kt_u;
};
struct curses_data
{
WINDOW *win;
struct
{
int x, y, tmarg, bmarg, valid;
chtype attr, bkgd;
} save;
char parm[8];
char nparm;
char bg; /* current background */
char fg; /* current foreground */
char flags;
#define C_ESC 0x01
#define C_CSI 0x02
#define C_INS 0x04
#define C_TTY 0x08
#define C_BOLD 0x10
};
static struct keytrie *keys;
/* mapping of IBM line-drawing characters to curses line drawing */
/* this is evil: it doesn't use e.g. ACS_HLINE because that's an array ref */
static chtype ibm_map[128] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
'a', 'a', 'a', 'x', 'u', 'u', 'u', 'k',
'k', 'u', 'x', 'k', 'j', 'j', 'j', 'k',
'm', 'v', 'w', 'u', 'q', 'n', 'u', 'u',
'j', 'l', 'v', 'w', 'u', 'q', 'n', 'v',
'v', 'w', 'w', 'm', 'm', 'l', 'l', 'n',
'n', 'j', 'l', 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
#ifdef M_UNIX
#define Getmaxy(w) getmaxy(w)
#define Getmaxx(w) getmaxx(w)
#else
static int
Getmaxy(WINDOW *w)
{
int y, x;
getmaxyx(w, y, x);
return y;
}
static int
Getmaxx(WINDOW *w)
{
int y, x;
getmaxyx(w, y, x);
return x;
}
#endif
static struct keytrie *
key_init(void)
{
struct keytrie *k;
int i;
k = mallocw(256 * sizeof *keys);
for (i = 256; i--; )
{
k[i].kt_type = KT_DEF;
k[i].kt_val = i;
}
return k;
}
static void
key_add(const char *str, int val)
{
const char *old;
struct keytrie *t;
int c;
/*
* Follow the trie until we get to the right subtrie for the string, then
* add the value. If we hit a KT_DEF, expand the trie. If we hit a KT_VAL
* change it to a KT_TVAL, which times out as a KT_VAL but continues as a
* KT_TRIE. If given a value for a KT_TRIE, change it to a KT_TVAL.
*/
if (!str || !*str)
return; /* no key to define */
old = str;
t = keys;
while (str[1])
{
c = uchar(*str++);
if (t[c].kt_type != KT_TRIE)
{
if (t[c].kt_type == KT_DEF)
t[c].kt_type = KT_TRIE;
else
{
t[c].kt_type = KT_TVAL;
t[c].kt_tval = t[c].kt_val;
}
t[c].kt_trie = key_init();
}
t = t[c].kt_trie;
}
c = uchar(*str);
if (t[c].kt_type == KT_TRIE)
{
t[c].kt_type = KT_TVAL;
t[c].kt_tval = val;
}
else if (t[c].kt_type == KT_DEF)
{
t[c].kt_type = KT_VAL;
t[c].kt_val = val;
}
}
#if 0
static int
map_colors(int bg, int fg)
{
int cp, cmask;
if (!color_pair_map)
return 0;
fprintf(stderr, "map_colors %d %d", bg, fg);
cmask = (bg << 4) | fg;
for (cp = 0; cp < COLOR_PAIRS; cp++)
{
if (color_pair_map[cp] == -1 || color_pair_map[cp] == cmask)
break;
}
if (cp == COLOR_PAIRS)
{fprintf(stderr, " - out of pairs!\n");
return 0;
}
if (color_pair_map[cp] == -1)
{
if (init_pair(cp + 1, fg, bg) == ERR)
{fprintf(stderr, "can't create pair %d\n", cp);
cp = 0;
}
else
{fprintf(stderr, " - new pair %d\n", cp);
color_pair_map[cp] = cmask;
}
}
else fprintf(stderr, " is pair %d\n", cp);
return COLOR_PAIR((cp + 1));
}
#endif
static int
curses_init(const struct sessmgr_sw *sm)
{
extern int Numrows, Numcols;
if (!isatty(0))
return 0;
if (initted)
{
#ifdef RAW_SESSMGR
set_curterm(my_term);
#endif
refresh(); /* bring curses back to life */
}
else
{
initscr(); /* be nice to trap errors... */
#if 0
/*
* I assume the curses manpage tells the truth when it claims that
* colors are initialized to RGB defaults. If not, I may need to set
* up the colors in question...
*/
if (has_colors() && start_color() != ERR && COLORS >= 8)
{
color_pair_map = mallocw(COLOR_PAIRS * sizeof *color_pair_map);
memset(color_pair_map, -1, COLOR_PAIRS * sizeof *color_pair_map);
map_colors(COLOR_BLACK, COLOR_WHITE); /* default color pair */
}
#endif
my_term = cur_term;
noecho();
nonl();
raw();
keys = key_init();
key_add(key_down, DNARROW);
key_add(key_f1, -3);
key_add(key_f2, -4);
key_add(key_f3, -5);
key_add(key_f4, -6);
key_add(key_f5, -7);
key_add(key_f6, -8);
key_add(key_f7, -9);
key_add(key_f8, -10);
key_add(key_f9, -11);
#ifdef M_UNIX
/* SCO botches it, as per usual */
key_add(key_f0, -2);
#else
key_add(key_f10, -2);
#endif
key_add(key_left, LTARROW);
key_add(key_right, RTARROW);
key_add(key_up, UPARROW);
key_add("\177", '\b'); /* so DEL behaves as BS */
initted = 1;
}
Suspense = 0;
Numrows = LINES;
Numcols = COLS;
return 1;
}
static void
curses_end(const struct sessmgr_sw *sm)
{
if (!Suspense)
endwin();
}
static void
curses_suspend(const struct sessmgr_sw *sm)
{
if (!Suspense++)
{
/* note that we use stdscr for this, since it's otherwise unoccupied */
clear();
refresh();
endwin();
}
}
static void
curses_resume(const struct sessmgr_sw *sm)
{
extern int Numrows, Numcols;
if (!--Suspense)
{
#ifdef RAW_SESSMGR
set_curterm(my_term);
#endif
clearok(((struct curses_data *) curscreen)->win, TRUE);
wrefresh(((struct curses_data *) curscreen)->win);
Numrows = LINES;
Numcols = COLS;
}
}
/*
* Options supported:
*
* tty, ansi
* Select old glass-tty emulation or new ANSI X3.64 emulation
*
* bold
* Specify style of highlight used
*/
static char *
curses_opts(const struct sessmgr_sw *sm, void *sp, char *opts)
{
struct curses_data *cp;
static char buf[1024];
char *xp, *ep;
size_t l;
cp = (struct curses_data *) sp;
if (!opts)
{
/* return printable version of options */
buf[0] = '\0';
if (cp->flags & C_TTY)
strcpy(buf, "tty");
if ((cp->flags & (C_TTY|C_BOLD)) == (C_TTY|C_BOLD))
strcat(buf, ",");
if (cp->flags & C_BOLD)
strcat(buf, "bold");
return buf;
}
/* parse and set options */
xp = opts;
while (*xp)
{
while (isspace(*xp) || *xp == ',')
xp++;
if (!*xp)
break;
l = 0;
for (ep = xp; *ep && *ep != ',' && !isspace(*ep); ep++)
l++;
memcpy(buf, xp, l);
buf[l] = '\0';
if (strcasecmp(buf, "tty") == 0)
cp->flags |= C_TTY;
else if (strcasecmp(buf, "ansi") == 0)
cp->flags &= ~C_TTY;
else if (strcasecmp(buf, "notty") == 0)
cp->flags &= ~C_TTY;
else if (strcasecmp(buf, "noansi") == 0)
cp->flags |= C_TTY;
else if (strcasecmp(buf, "bold") == 0)
cp->flags |= C_BOLD;
else if (strcasecmp(buf, "nobold") == 0)
cp->flags &= ~C_BOLD;
else
tprintf("curses: unknown option \"%s\"\n", buf);
xp = ep;
}
return 0;
}
static int
curses_swap(const struct sessmgr_sw *sm, void *old, void *new)
{
if (new)
{
clearok(((struct curses_data *) new)->win, TRUE);
touchwin(((struct curses_data *) new)->win);
curscreen = new;
}
return 1; /* can always run concurrent output */
}
static void
wiach(WINDOW *win, chtype ch, int insert)
{
if (insert)
winsch(win, (chtype) ch);
else
waddch(win, (chtype) ch);
}
static void
curses_putch(const struct sessmgr_sw *sm, void *dp, int c)
{
register struct curses_data *sp;
int x, y, ox, oy;
chtype attrs;
sp = dp;
if (c == 7)
{
write(1, "\7", 1);
return;
}
if (c == '\r' || c == '\b')
{
waddch(sp->win, (chtype) c);
return;
}
if (c == '\t')
{
wiach(sp->win, (chtype) c, sp->flags & C_INS);
return;
}
if (c == '\n')
{
/* waddch() does clrtoeol() implicitly. This breaks us. */
getyx(sp->win, y, x);
if (++y > sp->win->_bmarg)
{
y--;
scroll(sp->win);
}
wmove(sp->win, y, 0);
return;
}
if (sp->flags & C_TTY)
{
if (c >= 32 && c < 127)
wiach(sp->win, (chtype) c, sp->flags & C_INS);
return;
}
if (c == 24 || c == 26)
{
sp->flags &= ~(C_ESC|C_CSI);
return;
}
if (c == 27)
{
sp->flags |= C_ESC;
return;
}
if (c == '\016')
{
wattron(sp->win, A_ALTCHARSET);
return;
}
if (c == '\017')
{
wattroff(sp->win, A_ALTCHARSET);
return;
}
if (c < 32)
return;
if (!(sp->flags & (C_ESC|C_CSI)))
{
if (c > 127 && ibm_map[c - 128])
wiach(sp->win, ibm_map[c - 128] | A_ALTCHARSET, sp->flags & C_INS);
else if (c < 127)
wiach(sp->win, (chtype) c, sp->flags & C_INS);
return;
}
if (sp->flags & C_ESC)
{
/* we only handle '[' */
switch (c)
{
case '[':
sp->flags &= ~C_ESC;
sp->flags |= C_CSI;
sp->nparm = 0;
memset(sp->parm, 0, sizeof sp->parm);
break;
case '7':
getyx(sp->win, sp->save.y, sp->save.x);
sp->save.attr = getattrs(sp->win);
sp->save.tmarg = sp->win->_tmarg;
sp->save.bmarg = sp->win->_bmarg;
sp->save.bkgd = sp->win->_bkgd; /* should be a macro for this */
sp->save.valid = 1;
sp->flags &= ~(C_ESC|C_CSI);
break;
case '8':
if (sp->save.valid)
{
wmove(sp->win, sp->save.y, sp->save.x);
wattrset(sp->win, sp->save.attr);
wbkgdset(sp->win, sp->save.bkgd);
#ifdef linux
werase(sp->win); /* wbkgdset() doesn't do anything */
#endif
wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
sp->save.valid = 0;
}
sp->flags &= ~(C_ESC|C_CSI);
break;
default:
sp->flags &= ~(C_ESC|C_CSI);
break;
}
return;
}
/* handle CSI-sequences */
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
sp->parm[sp->nparm] = sp->parm[sp->nparm] * 10 + c - '0';
break;
case ';':
sp->parm[sp->nparm++] = 0;
break;
case '?':
/* just ignore it for now */
break;
/* action character */
case 'H':
case 'f':
wmove(sp->win, sp->parm[1] - 1, sp->parm[0] - 1);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'J':
switch (sp->parm[0])
{
case 0:
attrs = getattrs(sp->win);
wattrset(sp->win, A_NORMAL);
wclrtobot(sp->win);
wattrset(sp->win, attrs);
break;
case 1:
getyx(sp->win, oy, ox);
attrs = getattrs(sp->win);
wattrset(sp->win, A_NORMAL);
for (y = 0; y < oy; y++)
{
wmove(sp->win, y, 0);
for (x = Getmaxx(sp->win); x--; )
waddch(sp->win, ' ');
}
wmove(sp->win, oy, 0);
for (x = 0; x < ox; x++)
waddch(sp->win, ' ');
wattrset(sp->win, attrs);
break;
case 2:
wclear(sp->win);
break;
}
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'K':
switch (sp->parm[0])
{
case 0:
clrtoeol();
break;
case 1:
getyx(sp->win, oy, ox);
wmove(sp->win, oy, 0);
attrs = getattrs(sp->win);
wattrset(sp->win, A_NORMAL);
for (x = 0; x < ox; x++)
waddch(sp->win, ' ');
wattrset(sp->win, attrs);
break;
case 2:
getyx(sp->win, oy, ox);
wmove(sp->win, oy, 0);
attrs = getattrs(sp->win);
wattrset(sp->win, A_NORMAL);
for (x = Getmaxx(sp->win); x--; )
waddch(sp->win, ' ');
wmove(sp->win, oy, ox);
wattrset(sp->win, attrs);
break;
}
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'm':
sp->flags &= ~(C_ESC|C_CSI);
if (!sp->nparm)
{
wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
break;
}
for (x = 0; x < sp->nparm; x++)
{
switch (sp->parm[x])
{
case 0:
wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
break;
case 1:
wattron(sp->win, A_BOLD);
break;
case 2:
wattron(sp->win, A_DIM);
break;
case 4:
wattron(sp->win, A_UNDERLINE);
break;
case 5:
wattron(sp->win, A_BLINK);
break;
case 7:
wattron(sp->win, A_REVERSE);
break;
case 21:
wattroff(sp->win, A_BOLD);
break;
case 22:
wattroff(sp->win, A_DIM);
break;
case 24:
wattroff(sp->win, A_UNDERLINE);
break;
case 25:
wattroff(sp->win, A_BLINK);
break;
case 27:
wattroff(sp->win, A_REVERSE);
break;
/* ANSI color sequences? */
/* not for now; curses colors are too complex */
}
}
break;
case 'A':
getyx(sp->win, y, x);
if ((y -= (sp->nparm? sp->parm[0]: 1)) < 0)
y = 0;
wmove(sp->win, y, x);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'B':
getyx(sp->win, y, x);
if ((y += (sp->nparm? sp->parm[0]: 1)) >= Getmaxy(sp->win))
y = Getmaxy(sp->win) - 1;
wmove(sp->win, y, x);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'C':
getyx(sp->win, y, x);
if ((x += (sp->nparm? sp->parm[0]: 1)) >= Getmaxx(sp->win))
x = Getmaxx(sp->win) - 1;
wmove(sp->win, y, x);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'D':
getyx(sp->win, y, x);
if ((x -= (sp->nparm? sp->parm[0]: 1)) < 0)
x = 0;
wmove(sp->win, y, x);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'r':
wsetscrreg(sp->win, (sp->nparm? sp->parm[0] - 1: 0),
(sp->nparm > 1? sp->parm[1] - 1: Getmaxy(sp->win) - 1));
sp->flags &= ~(C_ESC|C_CSI);
break;
case 's':
getyx(sp->win, sp->save.y, sp->save.x);
sp->save.attr = getattrs(sp->win);
sp->save.tmarg = sp->win->_tmarg;
sp->save.bmarg = sp->win->_bmarg;
sp->save.bkgd = sp->win->_bkgd; /* should be a macro for this */
sp->save.valid = 1;
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'u':
if (sp->save.valid)
{
wmove(sp->win, sp->save.y, sp->save.x);
wattrset(sp->win, sp->save.attr);
wbkgdset(sp->win, sp->save.bkgd);
wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
sp->save.valid = 0;
}
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'L':
if (!sp->nparm)
sp->parm[0] = 1;
while (sp->parm[0]--)
winsertln(sp->win);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'M':
if (!sp->nparm)
sp->parm[0] = 1;
while (sp->parm[0]--)
wdeleteln(sp->win);
sp->flags &= ~(C_ESC|C_CSI);
break;
case '@':
if (!sp->nparm)
sp->parm[0] = 1;
while (sp->parm[0]--)
winsch(sp->win, ' ');
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'P':
if (!sp->nparm)
sp->parm[0] = 1;
while (sp->parm[0]--)
wdelch(sp->win);
sp->flags &= ~(C_ESC|C_CSI);
break;
case 'h':
case 'l':
for (x = 0; x < sp->nparm; x++)
{
switch (sp->parm[x])
{
case 4:
if (c == 'h')
sp->flags |= C_INS;
else
sp->flags &= ~C_INS;
break;
/* insert mode is all we handle right now */
}
}
sp->flags &= ~(C_ESC|C_CSI);
break;
default:
sp->flags &= ~(C_ESC|C_CSI);
break;
}
}
static void
curses_clreol(const struct sessmgr_sw *sm, void *dp)
{
wclrtoeol(((struct curses_data *) dp)->win);
}
static void
curses_rflush(const struct sessmgr_sw *sm, void *dp)
{
/* stub - later we'll update status here */
}
static void
curses_flush(const struct sessmgr_sw *sm, void *dp)
{
if (!Suspense && curscreen == dp)
wrefresh(((struct curses_data *) dp)->win);
}
static void *
curses_create(const struct sessmgr_sw *sm, struct session *sp)
{
struct curses_data *ssp;
ssp = mallocw(sizeof *ssp);
ssp->win = newwin(LINES, COLS, 0, 0);
scrollok(ssp->win, TRUE);
#if 0
ssp->bg = COLOR_BLACK; /* witness help 'em if they're in an xterm */
ssp->fg = COLOR_WHITE;
wbkgdset(ssp->win, COLOR_PAIR(1));
wattrset(ssp->win, COLOR_PAIR(1));
#endif
ssp->flags = 0;
ssp->save.valid = 0;
curscreen = ssp;
return ssp;
}
static void
curses_destroy(const struct sessmgr_sw *sm, void *dp)
{
delwin(((struct curses_data *) dp)->win);
j_free(dp);
}
static void
curses_clrscr(const struct sessmgr_sw *sm, void *dp)
{
WINDOW *w;
int l;
w = ((struct curses_data *) dp)->win;
for (l = w->_tmarg; l < w->_bmarg; l++)
{
wmove(w, l, 0);
wclrtoeol(w);
}
wmove(w, w->_tmarg, 0);
}
static int
curses_wherex(const struct sessmgr_sw *sm, void *dp)
{
int x, y;
getyx(((struct curses_data *) dp)->win, y, x);
return x + 1;
}
static int
curses_wherey(const struct sessmgr_sw *sm, void *dp)
{
WINDOW *w;
int x, y;
w = ((struct curses_data *) dp)->win;
getyx(w, y, x);
return y - w->_tmarg + 1;
}
static void
curses_window(const struct sessmgr_sw *sm, void *dp, int x1, int y1, int x2,
int y2)
{
WINDOW *w;
w = ((struct curses_data *) dp)->win;
wsetscrreg(w, y1 - 1, y2 - 1);
/* ttydriv() assumes the cursor is placed in this window somewhere */
wmove(w, y1 - 1, 0);
}
static void
curses_gotoxy(const struct sessmgr_sw *sm, void *dp, int x, int y)
{
WINDOW *w;
w = ((struct curses_data *) dp)->win;
wmove(w, y + w->_tmarg - 1, x - 1);
}
static void
curses_high(const struct sessmgr_sw *sm, void *dp)
{
wattron(((struct curses_data *) dp)->win,
(((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE);
}
static void
curses_norm(const struct sessmgr_sw *sm, void *dp)
{
wattroff(((struct curses_data *) dp)->win,
(((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE);
}
#if 0
static int
color_name(char *color)
{
if (strcasecmp(color, "black") == 0)
return COLOR_BLACK;
if (strcasecmp(color, "red") == 0)
return COLOR_RED;
if (strcasecmp(color, "yellow") == 0)
return COLOR_YELLOW;
if (strcasecmp(color, "green") == 0)
return COLOR_GREEN;
if (strcasecmp(color, "blue") == 0)
return COLOR_BLUE;
if (strcasecmp(color, "magenta") == 0)
return COLOR_MAGENTA;
if (strcasecmp(color, "cyan") == 0)
return COLOR_CYAN;
return COLOR_WHITE;
}
#endif
static void
curses_cursor(const struct sessmgr_sw *sm, void *dp, int c)
{
curs_set(c);
}
static int
kbchar(int ir)
{
extern int Keyboard;
unsigned char ch;
int i;
if (ir)
j_alarm(500);
do
{
if (pwait(&Keyboard) != 0 && ir)
return -1;
}
while ((i = read(0, &ch, 1)) == 0 || (i == -1 && errno == EWOULDBLOCK));
j_alarm(0);
if (i < 0)
{
tprintf("NOS PANIC: Lost keyboard\n");
where_outta_here(1);
}
return ch;
}
/*
* This remains incorrect. The keyboard process must be recreated as part of
* the session manager instead of being independent; this process must be
* capable of distributing input from several sources, including the real
* keyboard and external sessions.
*/
static int
curses_kbread(const struct sessmgr_sw *sm, void *dp)
{
static int ungets[10];
struct keytrie *t;
static int unget;
int ungetc[10];
int c, i, u;
i = 0;
u = 0;
if (unget > i)
c = ungets[i++];
else
c = kbchar(0);
ungetc[u++] = c;
t = keys;
while (t[c].kt_type == KT_TRIE || t[c].kt_type == KT_TVAL)
{
t = t[c].kt_trie;
if (unget > i)
c = ungets[i++];
else
c = kbchar(1);
if (c == -1)
break;
ungetc[u++] = c;
}
if (t[c].kt_type == KT_VAL)
{
u = 0;
c = t[c].kt_val;
}
else if (t[c].kt_type == KT_TVAL)
{
u = 0;
c = t[c].kt_tval;
}
while (i < unget)
ungetc[u++] = ungets[i++];
if (u)
{
c = ungetc[0];
for (i = u; i; i--)
ungets[i - 1] = ungetc[i];
unget = u - 1;
}
return c;
}
struct sessmgr_sw curses_sessmgr =
{
"curses",
SM_SPLIT|SM_STDIO,
curses_init,
(char *(*)__FARGS((const struct sessmgr_sw *, char *))) 0,
curses_create,
curses_opts,
curses_swap,
curses_putch,
curses_clreol,
curses_clrscr,
curses_wherex,
curses_wherey,
curses_window,
curses_gotoxy,
curses_high,
curses_norm,
curses_cursor,
curses_kbread,
curses_destroy,
0,
curses_rflush,
curses_flush,
curses_suspend,
curses_resume,
curses_end,
};
#endif